package tasks

import models.tasks._

import java.sql.Timestamp
import java.time.{LocalDate, LocalDateTime}
import javax.inject.Inject
import play.api.Logging
import services.dingtalk.DingtalkTasks
import services.intermediate.{BaseInfoUpdate, SendOutStockSum, SumOutStockRev}
import services.mes.{MoreMesBaseDoc, MoreMesMo, MoreMesStock}
import services.stockio.InStockAndReturnSave
import services.sysusers.SystemUsersTasks

import scala.concurrent.{ExecutionContext, Future}

class JobSchedules @Inject()(jobsRepo: JobsRepository,
                             jobExecRepo: JobExecutionsRepository,
                             sumOutStockRev: SumOutStockRev,
                             sendOutStockSum: SendOutStockSum,
                             dingtalkTask: DingtalkTasks,
                             baseInfoUpdate: BaseInfoUpdate,
                             inStockAndReturn: InStockAndReturnSave,
                             systemUsersTasks: SystemUsersTasks,
                             mesMoService: MoreMesMo,
                             mesStkServeice: MoreMesStock,
                             mesBaseDocServeice: MoreMesBaseDoc
                            )(implicit executionContext: ExecutionContext)
  extends Enumeration with Logging {

  type JobSchedules = Value
  val job1, sumOSR, sendOSS, dingTalk, bCodeUpdate, stockInAndOut, systemUsers, mesMo, mesStk, mesBaseDoc = Value

  def job(massage: JobInfo, jobSchedules: JobSchedules) = {
    if (DynamicJobSchedule.jobSchedules.contains(massage.id)) {
      val job = DynamicJobSchedule.jobSchedules(massage.id)
      DynamicJobSchedule.count += 1
      val timenow = Timestamp.valueOf(LocalDateTime.now())
      logger.debug(s"${timenow}(${job.next_run_time}) receive ${job.name}  = (${DynamicJobSchedule.count}) ${job.description}")
      val jobExecutionId = jobExecRepo.create(JobExecution(status = 1, started = Some(timenow), job_id = job.id, name = job.name))
      val reslog = jobSchedules match {
        case `job1` => Future(job1_worker)
        case `sumOSR` => Future(sumOSR_worker(massage.description))
        case `sendOSS` => Future(sendOSS_worker(massage.description))
        case `dingTalk` => dingTalk_worker(massage.description)
        case `bCodeUpdate` => Future(baseInfoUpdate_worker)
        case `stockInAndOut` => Future(stockInAndOut_worker)
        case `systemUsers` => Future(systemUsers_worker(massage.description))
        case `mesMo` => mesMoService_worker(massage.description)
        case `mesStk` => mesStkService_worker(massage.description)
        case `mesBaseDoc` => mesBaseDocService_worker(massage.description)
        case _ => Future(("no job", ""))
      }
      reslog.map { log =>
        val timenext = Timestamp.valueOf(LocalDateTime.now())
        val status = if (log._2.nonEmpty) 3 else 2
        jobExecutionId.map(id => jobExecRepo.update(id, status, Some(timenext), Some(log._1), Some(log._2)))
        val jobInfo = JobInfo(job.id, job.name, Some(timenext), None, job.description)
        DynamicJobSchedule.jobSchedules(job.id) = jobInfo
        1
      }
    } else {
      Future(1)
    }
  }

  private def job1_worker = {
    Thread.sleep(4_000)
    logger.debug("this is job1")
    (s"this is job1 (${LocalDateTime.now()})", "")
  }

  private def sumOSR_worker(d: Option[String] = None) = {
    val sumDate = if (d.nonEmpty) LocalDate.now else LocalDate.now.plusDays(-1)
    logger.debug(s"this is sumOSR_worker($sumDate")
    try {
      sumOutStockRev.osrSumAtDays(sumDate)
      (s"sumOSR_worker($sumDate) finished(${LocalDateTime.now()})", "")
    } catch {
      case e: Exception =>
        (s"sumOSR_worker as Exception(${LocalDateTime.now()})", e.toString)
    }

  }

  private def sendOSS_worker(d: Option[String] = None) = {
    logger.debug("this is sendOSS_worker()")
    try {
      if (d.nonEmpty) {
        sendOutStockSum.postAtDays()
        (s"sendOSS_worker postAtDays() finished(${LocalDateTime.now()})", "")
      } else {
        sendOutStockSum.postAtNotSend()
        (s"sendOSS_worker postAtNotSend() finished(${LocalDateTime.now()})", "")
      }
    } catch {
      case e: Exception =>
        (s"sendOSS_worker as Exception(${LocalDateTime.now()})", e.toString)
    }
  }

  private def dingTalk_worker(d: Option[String] = None) = {
    logger.debug("this is dingTalk_worker()")
    val company = d.getOrElse("")
    val dp = company match {
      case "wuyang" => 0
      case "rihua" => 20
      case "lidun" => 40
      case _ => 59
    }
    try {
      val nowTime = LocalDateTime.now()
      val allupdate = if (nowTime.getHour == 22 && nowTime.getMinute >= dp && nowTime.getMinute < dp + 10) true else false
      if (nowTime.getHour >= 23 || nowTime.getHour <= 6) {
        Future((s"dingTalk_worker($company) finished, (23H-6H)", ""))
      } else {
        dingtalkTask.contentUpdateTask(d.getOrElse(""), allupdate).map {
          res =>
            (s"dingTalk_worker($company) finished, allUpdate: $allupdate, $res", "")
        }
      }
    } catch {
      case e: Exception =>
        Future((s"dingTalk_worker($company) as Exception", e.toString))
    }
  }

  private def baseInfoUpdate_worker = {
    logger.debug("this is baseInfoUpdate_worker()")
    try {
      val r = baseInfoUpdate.sameCodeUpdate()
      (s"baseInfoUpdate_worker finished(${LocalDateTime.now()}), $r", "")
    } catch {
      case e: Exception =>
        (s"baseInfoUpdate_worker as Exception(${LocalDateTime.now()})", e.toString)
    }
  }

  private def stockInAndOut_worker = {
    logger.debug("this is stockInAndOut_worker()")
    val nowTime = LocalDateTime.now()
    if (nowTime.getHour >= 9) {
      try {
        inStockAndReturn.stockInAndOut()
        (s"stockInAndOut_worker finished(${LocalDateTime.now()})", "")
      } catch {
        case e: Exception =>
          (s"stockInAndOut_worker as Exception(${LocalDateTime.now()})", e.toString)
      }
    } else
      (s"stockInAndOut_worker finished(${LocalDateTime.now()})", "")
  }

  private def systemUsers_worker(d: Option[String] = None) = {
    logger.debug("this is systemUsers_worker()")

    try {
      systemUsersTasks.systemUsersTask()
      (s"systemUsers_worker($d) finished(${LocalDateTime.now()})", "")
    } catch {
      case e: Exception =>
        (s"systemUsers_worker as Exception(${LocalDateTime.now()})", e.toString)
    }
  }

//  private def gyQimenService_worker(d: Option[String] = None) = {
//    try {
//      val t = "^[0-9]".r.replaceAllIn(d.getOrElse("10"), "").toInt
//      val step = if (t < 5) 5 else t
//      gyQimenService.gyQimenTask(step).map(res =>
//        (s"gyQimenService_worker_worker finished(${LocalDateTime.now()})", "")
//      )
//    } catch {
//      case e: Exception =>
//        Future((s"gyQimenService_worker_worker as Exception(${LocalDateTime.now()})", e.toString))
//    }
//  }

  private def mesMoService_worker(d: Option[String] = None) = {
    val arg = d.getOrElse("").split("\\W")
    val service = if (arg.length >= 2) {
      if ("\\d+[DdHhMmSs]".r.matches(arg(0))) {
        mesMoService.setConfig(arg(1)).setStepTime(arg(0))
      } else if ("\\d+[DdHhMmSs]".r.matches(arg(1))) {
        mesMoService.setConfig(arg(0)).setStepTime(arg(1))
      } else {
        mesMoService.setConfig(arg(0))
      }
    }
    else if ("\\d+[DdHhMmSs]".r.matches(arg(0))) {
      mesMoService.setStepTime(arg(0))
    }
    else {
      mesMoService.setConfig(arg(0))
    }
    try {
      service.runTask().map(res => {
        logger.debug(res.toString)
        (s"mesMoService_worker finished(${LocalDateTime.now()})", "")
      }
      )
    } catch {
      case e: Exception =>
        Future((s"mesMoService_worker as Exception(${LocalDateTime.now()})", e.toString))
    }
  }

  private def mesStkService_worker(d: Option[String] = None) = {
    val arg = d.getOrElse("").split("\\W")
    val service = if (arg.length >= 2) {
      if ("\\d+[DdHhMmSs]".r.matches(arg(0))) {
        mesStkServeice.setConfig(arg(1)).setStepTime(arg(0))
      } else if ("\\d+[DdHhMmSs]".r.matches(arg(1))) {
        mesStkServeice.setConfig(arg(0)).setStepTime(arg(1))
      } else {
        mesStkServeice.setConfig(arg(0))
      }
    }
    else if ("\\d+[DdHhMmSs]".r.matches(arg(0))) {
      mesStkServeice.setStepTime(arg(0))
    }
    else {
      mesStkServeice.setConfig(arg(0))
    }
    try {
      service.runTask().map(res =>
        (s"mesStkService_worker finished(${LocalDateTime.now()})", "")
      )
    } catch {
      case e: Exception =>
        Future((s"mesStkService_worker as Exception(${LocalDateTime.now()})", e.toString))
    }
  }

  private def mesBaseDocService_worker(d: Option[String] = None) = {
    val arg = d.getOrElse("").split("\\W")
    val service = if (arg.length >= 2) {
      if ("\\d+[DdHhMmSs]".r.matches(arg(0))) {
        mesBaseDocServeice.setConfig(arg(1)).setStepTime(arg(0))
      } else if ("\\d+[DdHhMmSs]".r.matches(arg(1))) {
        mesBaseDocServeice.setConfig(arg(0)).setStepTime(arg(1))
      } else {
        mesBaseDocServeice.setConfig(arg(0))
      }
    }
    else if ("\\d+[DdHhMmSs]".r.matches(arg(0))) {
      mesBaseDocServeice.setStepTime(arg(0))
    }
    else {
      mesBaseDocServeice.setConfig(arg(0))
    }
    try {
      service.runTask().map(res =>
        (s"mesBaseDocService_worker finished(${LocalDateTime.now()})", ""))

    } catch {
      case e: Exception =>
        Future((s"mesBaseDocService_worker as Exception(${LocalDateTime.now()})", e.toString))
    }
  }

}
